package com.laobiao.file_netty_lib.netty.client.handler;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.laobiao.file_netty_lib.content.LoggerUtil;
import com.laobiao.file_netty_lib.exception.FileBaseException;
import com.laobiao.file_netty_lib.netty.client.ClientBusiness;
import com.laobiao.file_netty_lib.packet.BasePacket;
import com.laobiao.file_netty_lib.packet.command.ResoultCommand;
import com.laobiao.file_netty_lib.packet.command.upload.FileUploadCommand;
import com.laobiao.file_netty_lib.packet.data.BaseDataPacket;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
/**
 * 客户端文件上传业务类
 * @author 38079
 *
 */
public class ClientFileUploadBusiness extends FileUploadCommand implements ClientBusiness{
	private static final Logger logger=LoggerUtil.getLogger(ClientFileUploadBusiness.class);
	/**
	 * 本地文件输入流
	 */
	private volatile FileInputStream fileIn;
	/**
	 * 整个流程是否停止，异常或正常上传完成后置true
	 */
	private volatile boolean stop=false;
	
	/**
	 * 是否上传成功，流程完成且正常上传成功是置true
	 */
	private volatile boolean upload=false;
	
	/**
	 * 服务端反馈的消息
	 */
	private String msg="";
	
	private File localFile;
	
	private Channel channel;
	
	/**
	 * 构建
	 * @param localFile
	 * @param remoteFilePath
	 * @param commandGroup
	 */
	public ClientFileUploadBusiness(File localFile, String remoteFilePath,int businessGroup,Channel channel) {
		super(localFile, remoteFilePath, businessGroup);
		this.localFile=localFile;
		this.channel=channel;
		createReader(localFile);
	}
	
	private void createReader(File localFile) {
		try {
			fileIn = new FileInputStream(localFile);
		}catch (Exception e) {
			// TODO: handle exception
			throw new FileBaseException("读取本地文件失败！", e,FileBaseException.ERR_PARAM_WRONG);
		}
	}
	
	/**
	 * 写入远端错误消息
	 * @param msg
	 */
	private  void err(String msg) {
		setStatus(true,false,msg);
	}
	
	/**
	 * 执行成功
	 * @param msg
	 */
	private  void sucess(String msg) {
		setStatus(true,true,msg);
	}
	
	private  void setStatus(boolean stop,boolean upload,String msg) {
		this.stop=stop;
		this.upload=upload;
		this.msg=msg;
		if(stop) {//停止
			close();
		}
	}
	
	public void resoultPacket(BasePacket packet) {
		logger.log(Level.CONFIG,"收到服务端发来的反馈命令包！"+packet);
		/**
		 * 上传只会接收反馈命令包，其他包不管
		 */
		if (packet instanceof ResoultCommand) {
			ResoultCommand reCommand = (ResoultCommand) packet;
			if (reCommand.isStatus()) {//成功状态
				if (reCommand.getCode() == ResoultCommand.ResoultCode.Common.SERVER_RECEIVE) {// 接收过程中成功的状态信息
					
				} else if (reCommand.getCode() == ResoultCommand.ResoultCode.Common.SERVER_CHECK) {// 校验完成入库的成功信息
					logger.info("文件"+localFile.getAbsolutePath()+"上传成功！");
					sucess(reCommand.getMessage());
					close();
				}
			} else {//失败状态
				logger.warning("上传失败！"+reCommand.getMessage());
				err(reCommand.getMessage());
				close();
			}
		}
	}
	
	/**
	 * 读取文件
	 * @param b
	 * @return
	 */
	public int read(byte[] b) {
		if(stop) {
			if(!upload) {
				throw new FileBaseException(msg, FileBaseException.ERR_PARAM_WRONG);
			}else {
				return -1;//执行完成了
			}
		}
		try {
			return fileIn.read(b);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw new FileBaseException("读取本地文件失败！", e,FileBaseException.ERR_PARAM_WRONG);
		}
	}
	
	/**
	 * 流程操作完成后必须调用close()方法释放资源
	 */
	public void close() {
		try {
			fileIn.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 检测是否上传成功
	 * @param timeOutSeconds 超时时间
	 * @return
	 */
	public boolean isUpload(int timeOutSeconds) {
		long defaultSleepTime=100;
		long millisecond=timeOutSeconds*1000;
		while(!stop && millisecond>0) {
			millisecond-=defaultSleepTime;
			try {
				Thread.currentThread().sleep(defaultSleepTime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if(!stop) {
			throw new FileBaseException("上传文件超时！", FileBaseException.ERR_PARAM_WRONG);
		}
		return upload;
	}

	@Override
	public Object executStatus(int executReturnTimeOutSeconds) {
		// TODO Auto-generated method stub
		channel.writeAndFlush(this);
		try {
			byte[] b = new byte[1015];
			int readSize = 0;
			long start=System.currentTimeMillis();
			while ((readSize = read(b)) != -1) {
				BaseDataPacket dataPacket = new BaseDataPacket(getBusinessGroup(), b);
				dataPacket.setContentSize(readSize);
				ChannelFuture fs = channel.writeAndFlush(dataPacket);
				fs.sync();
				b = new byte[1015];
			}
			long sendTime=System.currentTimeMillis()-start;
			double sendSeconde=(sendTime)/1000.0000;
			logger.info("文件【"+localFile.getAbsolutePath()+"】发送完成：\n\r    用时:"+sendSeconde+"秒,速度:"+(getFileSize()/1024.000/sendSeconde)+"KB/秒");
			
			// 发送上传完成命令包
			ResoultCommand reCommad = new ResoultCommand(ResoultCommand.ResoultCode.Upload.CLIENT_UPLOAD, "客户端上传完成！",
					true, getBusinessGroup());
			channel.writeAndFlush(reCommad);
			return isUpload(executReturnTimeOutSeconds);
		} catch (FileBaseException e) {
			throw e;
		}catch (Exception e) {
			ResoultCommand reCommad = new ResoultCommand(ResoultCommand.ResoultCode.Upload.CLIENT_UPLOAD,
					"客户端上传失败！" + e.getMessage(), false, getBusinessGroup());
			channel.writeAndFlush(reCommad);
			throw new FileBaseException("读取文件失败！", e, FileBaseException.ERR_PARAM_WRONG);
		} finally {
			close();
		}
	}

	@Override
	public Channel getChannel() {
		// TODO Auto-generated method stub
		return this.channel;
	}


	
}
